﻿using System.ComponentModel.Composition;
using SS.WPF.Framework.Selection;
using SS.WPF.Framework.ViewModel.Screen;

namespace SS.WPF.Framework.ViewModel.Navigation
{
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// The abstract class implement interface INavigationCatalog is used to present a catalog
    /// </summary>
    public abstract class NavigationBase<T> : ViewModelBase, INavigationCatalog, ISelectionChangedHandler where T : class, INavigationNode
    {
        private IList<T> _children;

        /// <summary>
        /// The list NavigationNode of NavigationCatelog
        /// </summary>
        public IList<T> Children
        {
            get
            {
                return this._children;
            }
            set
            {
                this._children = value;
                this.NotifyOfPropertyChange(() => this.Children);

            }
        }

        #region Implementation of INavigationCatalog

        public object[] NavigationItems
        {
            get
            {
                if (this.Children == null)
                {
                    return new object[0];
                }

                return this.Children.Cast<object>().ToArray();
            }
        }

        private bool _isExpanded = true;

        /// <summary>
        /// Determines whether Navigation catalog is expended
        /// <para>
        /// Default value is true
        /// </para>
        /// </summary>
        public bool IsExpanded
        {
            get
            {
                return this._isExpanded;
            }
            set
            {
                this._isExpanded = value;
                this.NotifyOfPropertyChange(() => this.IsExpanded);
            }
        }

        private T _selectedItem;

        /// <summary>
        /// Refer to the Navigation node has been selected
        /// </summary>
        public T SelectedItem
        {
            get
            {
                return this._selectedItem;
            }
            set
            {
                if (!ReferenceEquals(_selectedItem, value))
                {
                    this._selectedItem = value;
                    this.NotifyOfPropertyChange(() => this.SelectedItem);
                }
            }
        }

        [Import]
        public ISelectionService SelectionService { get; set; }

        #endregion

        #region Overrides of Screen

        protected override void OnInitialize()
        {
            if (this.SelectionService != null)
            {
                this.SelectionService.Register(this);
            }

            base.OnInitialize();
        }

        #endregion

        #region Event handlers

        /// <summary>
        /// This method is invoke to execute when user change selection on NavigationCatalog
        /// </summary>
        /// <param name="currentItem">Selected item</param>
        public void OnSelectedItemChanged(T currentItem)
        {
            if (SelectionService != null)
            {
                this.SelectedItem = currentItem;
                if (this.SelectedItem != null)
                {
                    SelectionService.SetSelection(this, new StructureSelection(currentItem));
                }
            }
        }

        #endregion

        #region Implementation of ISelectionChangedHandler

        public virtual void SelectionChanged(object sender, ISelection newSelection)
        {
            if (!ReferenceEquals(this, sender))
            {
                if (newSelection != null && !newSelection.IsEmpty && newSelection is StructureSelection)
                {
                    var structureSelection = (StructureSelection) newSelection;
                    var node = structureSelection.GetFirst() as INavigationNode;

                    if (!ReferenceEquals(SelectedItem, node))
                    {
                        if (this.SelectedItem != null)
                        {
                            this.SelectedItem.IsSelected = false;
                            this.SelectedItem = default(T);
                        }
                    }
                }
            }
        }

        #endregion

        #region Implementation of IDisposable

        public void Dispose()
        {
            this.SelectionService.Unregister(this);
        }

        #endregion
    }
}
